package m.html.form;

import m.common.model.Model;
import m.html.element.Button;
import m.html.element.Element;
import m.html.element.Icon;
import m.html.element.Text;
import m.html.element.attr.Align;
import m.html.element.attr.ButtonType;
import m.html.element.attr.Size;
import m.html.element.other.IElement;
import m.system.util.JSONMessage;
import m.system.util.StringUtil;

import java.util.*;

public class TableForm implements IForm {
    private final boolean showHead;
    private final String title;//标题
    private String subTitle="";//子标题
    private String test;
    private String mounted;
    private TableColumn editCol;
    private boolean addAndRemove=false;
    private boolean removeFlag=true;
    private String addDefault="{}";
    private String dataKey;
    private List<? extends Model> dataList;
    private final List<ITableColumn> cols=new ArrayList<>();//内容
    private final List<FormButton> buttons=new ArrayList<>();//按钮项
    private final List<FormEvent> events=new ArrayList<>();
    private final Map<String,String> watchMap=new HashMap<>();
    private String editRowConfirm;
    private String rowChangeAfter;
    public TableForm(String title){
        this(title,true);
    }
    public TableForm(String title,boolean showHead){
        this.title=title;
        this.showHead=showHead;
    }

    @Override
    public boolean isShowHead() {
        return this.showHead;
    }

    public TableForm addColumn(ITableColumn... col){
        this.cols.addAll(Arrays.asList(col));
        for(ITableColumn c : col) this.events.addAll(Arrays.asList(c.getLinks()));
        return this;
    }

    /** 子标题
     * 支持标签和表达式
     */
    public TableForm setSubTitle(String subTitle) {
        this.subTitle = subTitle;
        return this;
    }

    /**
     * 设置表达式 显示或隐藏
     */
    public TableForm setTest(String ifTest){
        this.test=ifTest;
        return this;
    }
    /**
     * 设置是否可编辑
     */
    public TableForm setEdit(boolean edit){
        return setEdit(edit,false,"{}");
    }

    /**
     * 设置是否可编辑
     * 是否有新增
     * 添加的默认对象
     */
    public TableForm setEdit(boolean edit,boolean addAndRemove,String addDefault){
        return setEdit(edit,addAndRemove,addDefault,true);
    }
    /**
     * 设置是否可编辑
     * 是否有新增
     * 添加的默认对象
     * 删除标识，
     *    true：增加deleteFlag=1表示删除（Model包含字段deleteFlag，0:正常,1:删除，id不会变），
     *    false：直接删除（建议删除全部后再插入，id会发生变化）
     */
    public TableForm setEdit(boolean edit,boolean addAndRemove,String addDefault,boolean removeFlag){
        if(edit) {
            this.editCol = new TableColumn("操作","oper",Align.CENTER,120)
            .setFixed(Align.RIGHT)
            .setShow(Element.tag("a-space").E(
                new Button(Size.SMALL, ButtonType.PRIMARY).A("v-if","!record.deleteFlag")
                    .E("修改").A("@click","selectEditRow(index,record)"),
                addAndRemove?new Button(Size.SMALL, ButtonType.WARN).A("v-if","!record.deleteFlag")
                    .E("删除").A("@click","removeEditRow(index)"):null,
                addAndRemove?new Button(Size.SMALL, ButtonType.SUCCESS).A("v-if","record.deleteFlag==1")
                    .E("恢复").A("@click","resetEditRow(index)"):null

            ))
            .setEdit(TableEdit.show(
                Element.tag("a-space").E(
                    new Button(Size.SMALL, ButtonType.LINK)
                        .E(new Icon("icon-icon-58")).A("@click","confirmEditRow(index)"),
                    new Button(Size.SMALL, ButtonType.LINK_ERROR)
                        .E(new Icon("icon-icon-57")).A("@click","cancelEditRow(index)")
                )
            ));
        }else{
            this.editCol=null;
        }
        this.addAndRemove=addAndRemove;
        this.addDefault=addDefault;
        this.removeFlag=removeFlag;
        return this;
    }

    /**
     * 添加按钮
     */
    public TableForm addButton(FormButton... button){
        this.buttons.addAll(Arrays.asList(button));
        return this;
    }

    /**
     * 设置页面加载后执行的js
     */
    public TableForm setMounted(String mounted) {
        this.mounted = mounted;
        return this;
    }

    /**
     * 添加表单数据
     */
    public TableForm setData(String key, List<? extends Model> data){
        this.dataKey=key;
        this.dataList= data;
        return this;
    }

    /**
     * 设置编辑行确认后执行的方法 方法有一个参数(行数据)
     */
    public TableForm setEditRowConfirm(String method){
        this.editRowConfirm=method;
        return this;
    }

    /**
     * 设置任意行发生变化后执行的方法，没有参数
     */
    public TableForm setRowChangeAfter(String method){
        this.rowChangeAfter=method;
        return this;
    }
    /**
     * 添加属性监听
     */
    public TableForm addWatch(String dataKey,String js){
        this.watchMap.put(dataKey,js);
        return this;
    }

    /**
     * 添加方法
     */
    public TableForm addMethod(FormEvent... event){
        this.events.addAll(Arrays.asList(event));
        return this;
    }
    private boolean fillSumElement(List<Element> ls,StringBuilder colTemplate,TableColumn col){
        boolean hasSum=false;
        colTemplate.append(col.getCustomRender());
        if (col.getSum()) {
            hasSum = true;
            ls.add(
                    Element.tag("a-table-summary-cell")
                            .E(
                                    Element.tag("div").A(":style", "{textAlign:'" + col.getAlign() + "'}")
                                            .E(new Text("{{formatter('',sumDataRow(item=>item.deleteFlag==1?0:parseFloat(item." + col.getField() + ")),'" + col.getNumberFormat() + "')}}"))
                            )
            );
        } else {
            ls.add(Element.tag("a-table-summary-cell"));
        }
        return hasSum;
    }
    @Override
    public IElement getElement(boolean hasBack) {
        int width=0;
        for(ITableColumn col : cols){
            if(col instanceof TableColumn) {
                width += ((TableColumn)col).getWidth();
            }else{
                for(TableColumn c : ((TableGroup)col).getColumns()){
                    width += c.getWidth();
                }
            }
        }
        Element table;
        if(StringUtil.isSpace(this.dataKey)) {
            table=Element.tag("").E("未设置Data属性");
        }else{
            StringBuilder colTemplate=new StringBuilder();
            List<Element> ls=new ArrayList<>();
            boolean hasSum=false;
            for(ITableColumn col : cols) {
                if(col instanceof TableColumn) {
                    if(fillSumElement(ls,colTemplate,(TableColumn) col)){
                        hasSum=true;
                    }
                }else{
                    for(TableColumn c : ((TableGroup)col).getColumns()){
                        if(fillSumElement(ls,colTemplate,c)){
                            hasSum=true;
                        }
                    }
                }
            }
            if(null!=editCol) colTemplate.append(editCol.getCustomRender());
            table = Element.tag("a-table")
                .A(":scroll", "{x:"+width+"}").A("class","index-table")
                .A("size", "small").A(":columns", "tableCols").A(":data-source", this.dataKey)
                .A(":pagination","false").A("tableLayout", "fixed")
                .E(colTemplate.toString());
            if(hasSum){
                table.E(
                    Element.tag("template").A("#summary")
                    .E(
                        Element.tag("a-table-summary").A("fixed")
                        .E(Element.tag("a-table-summary-row").E(ls))
                    )
                );
            }
        }

        Element ele=new Element("a-page-header");
        ele
        .E(
            Element.tag("template").A("#title").E(new Text(this.title))
        )
        .E(
            Element.tag("template").A("#subTitle").E(new Text(this.subTitle))
        )
        .E(
            Element.tag("template").A("#extra")
            .E(Element.tag("span").A("class","text-red padding-sm").E("<b>{{editRowIndex>=0?('第'+(editRowIndex+1)+'行编辑中…'):''}}</b>"))
            .E(this.buttons)
            .E(null!=editCol&&addAndRemove?new Button(ButtonType.PRIMARY).E("添加").A("@click","addEditRow"):null)
            .E(
                hasBack?Element.tag("m-back").E(new Text("{{param.openType=='PAGE'?'返回':'关闭'}}")).setExtend(" v-if=\"param.isOpen\" @click=\"back(false);\" "):null
            )
        )
        .E(
            Element.tag("a-card").A("hoverable").A(":bodyStyle","{padding:0}")
            .E(table)
        );
        return ele;
    }
    private JSONMessage toFieldJson(TableColumn col){
        JSONMessage json=new JSONMessage();
        json.push("title",col.getTitle());
        json.push("width",col.getWidth());
        json.push("key",col.getField());
        json.push("dataIndex",col.getField().split("\\."));
        json.push("align",col.getAlign().toString());
        if(null!=col.getFixed()){
            json.push("fixed",col.getFixed()== Align.CENTER?true:col.getFixed().toString());
        }
        json.push("slots",new JSONMessage().push("customRender",col.getField().replaceAll("\\.", "_")));
        return json;
    }
    @Override
    public String getMounted() {
        StringBuilder str= new StringBuilder();
        for(ITableColumn col : cols){
            JSONMessage json;
            if(col instanceof TableColumn) {
                json=toFieldJson((TableColumn)col);
            }else{
                json=new JSONMessage();
                json.push("title",col.getTitle());
                List<JSONMessage> ls=new ArrayList<>();
                for(TableColumn c : ((TableGroup)col).getColumns()){
                    ls.add(toFieldJson(c));
                }
                json.push("children",ls);
            }
            str.append("this.tableCols.push(").append(json.toJSONString()).append(");");
        }
        if(null!=this.editCol){
            JSONMessage json=new JSONMessage();
            json.push("title",this.editCol.getTitle());
            json.push("width",this.editCol.getWidth());
            json.push("key",this.editCol.getField());
            json.push("dataIndex",this.editCol.getField().split("\\."));
            json.push("align",this.editCol.getAlign());
            json.push("fixed",this.editCol.getFixed());
            json.push("slots",new JSONMessage().push("customRender",this.editCol.getField()));
            str.append("this.tableCols.push(").append(json.toJSONString()).append(");");
        }
        return str+StringUtil.noSpace(mounted);
    }
    @Override
    public Map<String,Object> getData() {
        Map<String,Object> map=new HashMap<>();
        map.put("tableCols",new ArrayList<>());
        map.put(dataKey,dataList);
        map.put("editRowIndex",-1);//当前编辑行索引
        map.put("editRecord",null);//当前编辑行记录
        map.put("addAndRemove",addAndRemove);//是否有添加和删除
        return map;
    }

    @Override
    public List<FormEvent> getMethods() {
        List<FormEvent> ls = new ArrayList<>(this.events);
        ls.add(FormEvent.custom("selectEditRow(index,record)",//进入行编辑
            "if(this.editRowIndex>=0) this.confirmEditRow(this.editRowIndex);" +
            "this.editRowIndex=index;" +
            "this.editRecord=JSON.parse(JSON.stringify(record));"
        ));
        ls.add(FormEvent.custom("confirmEditRow(index)",//行编辑保存
            "this."+dataKey+"[index]=this.editRecord;"+
            "this.editRowIndex=-1;" +
            "this.editRecord=null;"
            +(StringUtil.notSpace(editRowConfirm)?("this."+editRowConfirm+"(this."+dataKey+"[index]);"):"")//编辑确认后
            +(StringUtil.notSpace(rowChangeAfter)?("this."+rowChangeAfter+"();"):"")//行发生变化
        ));
        ls.add(FormEvent.custom("cancelEditRow(index)",//取消行编辑
            "this.editRowIndex=-1;" +
            "this.editRecord=null;"
        ));
        ls.add(FormEvent.custom("removeEditRow(index)",//移除行
            "if(this.editRowIndex>=0) this.confirmEditRow(this.editRowIndex);" +
            "if(this."+dataKey+"[index].oid && "+removeFlag+") this."+dataKey+"[index].deleteFlag=1;" +
            " else delete this."+dataKey+"[index];" +
            "this."+dataKey+"=this."+dataKey+".filter(item => null!==item);"
            +(StringUtil.notSpace(rowChangeAfter)?("this."+rowChangeAfter+"();"):"")//行发生变化
        ));
        ls.add(FormEvent.custom("resetEditRow(index)",//恢复行
            "if(this.editRowIndex>=0) this.confirmEditRow(this.editRowIndex);" +
            "delete this."+dataKey+"[index].deleteFlag;"
            +(StringUtil.notSpace(rowChangeAfter)?("this."+rowChangeAfter+"();"):"")//行发生变化
        ));
        ls.add(FormEvent.custom("addEditRow",//添加行
            "this."+dataKey+".push("+addDefault+");" +
            "this.selectEditRow(this."+dataKey+".length-1,this."+dataKey+"[this."+dataKey+".length-1]);"
        ));
        ls.add(FormEvent.custom("sumDataRow(fn)",//合计列方法
            "let d=0;" +
            "for(let i=0;i<this."+dataKey+".length;i++){if(this."+dataKey+"[i]){d+=fn(this."+dataKey+"[i])||0;}}" +
            "return d;"
        ));
        return ls;
    }
    @Override
    public Map<String, String> getWatch() {
        return this.watchMap;
    }

    @Override
    public String getTest() {
        return test;
    }
}
